﻿using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using FarseerGames.FarseerPhysics.Collisions;
using FarseerGames.FarseerPhysics.Mathematics;
using FreeGoo.GameEngine;
using FreeGoo.GameEngine.Interfaces;
using FreeGoo.GameEngine.Renderables;
using FreeGoo.GameEngine.Renderables.Links;
using FreeGoo.GameEngine.Renderables.Particles;
using FreeGoo.GameEngine.Renderables.Particles.Keys;
using FreeGoo.WpfRenderer.Constants;

namespace FreeGoo.WpfRenderer
{
    public class RendererFactory : IRendererFactory
    {
        private Dictionary<string, BitmapImage> _bitmapImages = new Dictionary<string, BitmapImage>();
        
        public RendererFactory(Canvas canvas)
        {
            Canvas = canvas;
        }

        public Engine Engine { get; set; }
        public Canvas Canvas { get; set; }        

        public static Polyline CreatePolylineFromGeom(Geom geom)
        {
            Polyline polyline = new Polyline();
            foreach (Vector2 vertex in geom.LocalVertices)
            {
                polyline.Points.Add(new Point(vertex.X, vertex.Y));
            }

            // Close the path
            Vector2 closeCertex = geom.LocalVertices[0];
            polyline.Points.Add(new Point(closeCertex.X, closeCertex.Y));
            polyline.Stroke = BrushConstants.Black;
            return polyline;
        }

        public static Polygon CreatePolygonFromGeom(Geom geom)
        {
            Polygon polygon = new Polygon();
            foreach (Vector2 vertex in geom.LocalVertices)
            {
                polygon.Points.Add(new Point(vertex.X, vertex.Y));
            }

            // Close the path
            Vector2 closeCertex = geom.LocalVertices[0];
            polygon.Points.Add(new Point(closeCertex.X, closeCertex.Y));
            polygon.Stroke = BrushConstants.Black;
            return polygon;
        }

        public static Color GetColorForLinkable(ILinkable linkable)
        {
            Color color;

            if (linkable is Chain)
            {
                color = ColorConstants.Aqua;
            }
            else if (linkable is Rope)
            {
                color = ColorConstants.Crimson;
            }
            else if (linkable is MultiLink)
            {
                color = ColorConstants.LightGreen;
            }
            else if (linkable is FixedHook)
            {
                color = ColorConstants.Brown;
            }
            else if (linkable is Simple)
            {
                color = ColorConstants.DarkGray;
            }
            else if (linkable is Balloon)
            {
                color = ColorConstants.Pink;
            }
            else if (linkable is Strong)
            {
                color = ColorConstants.DarkRed;
            }
            else if (linkable is Key)
            {
                if (linkable is KeyedMotorKey)
                {
                    if ((linkable as KeyedMotorKey).Direction == GameEngine.Renderables.BodyHookOwners.KeyedMotor.Direction.Forward)
                    {
                        color = ColorConstants.DarkGreen;
                    }
                    else
                    {
                        color = ColorConstants.DarkRed;
                    }
                }
                else
                {
                    color = ColorConstants.Beige;
                }
            }
            else
            {
                color = ColorConstants.Beige;
            }

            return color;
        }

        public void SetRenderer(Renderable renderable)
        {
            if (renderable.Renderer == null)
            {
                renderable.Renderer = CreateRenderer(renderable);
            }
        }

        public void UpdateRenderer(Renderable renderable, GraphicsArgument graphicsArgument)
        {
            ImageRenderer imageRenderer = CreateImageRenderer(renderable, graphicsArgument.ImageName, graphicsArgument.Offset);

            if (renderable.Renderer != null)
            {
                renderable.Renderer.Delete();
            }

            renderable.Renderer = imageRenderer;
        }

        public BitmapImage GetOrCreateBitmapImage(string imageName, Color color)
        {
            string key = imageName.ToLowerInvariant() + color.ToString();
            if (!_bitmapImages.ContainsKey(key))
            {
                BitmapImage bitmapImage = BitmapImageUtils.LoadAndColorizeBitmapImage(imageName, color);
                _bitmapImages.Add(key, bitmapImage);
                return bitmapImage;
            }

            return _bitmapImages[key];
        }
        
        public IRenderer CreateRenderer(Renderable renderable)
        {
            if (renderable is Particle)
            {
                return CreateParticleRenderer(renderable as Particle);
            }
            else if (renderable is BodyRenderable)
            {
                return CreateFallbackBodyRenderer(renderable as BodyRenderable);
            }
            else if (renderable is Link)
            {
                return CreateLinkRenderer(renderable as Link);
            }
            else if (renderable is Goal)
            {
                return CreateGoalRenderer(renderable as Goal);
            }
            else if (renderable is BodyHook)
            {
                return CreateBodyHookRenderer(renderable as BodyHook);
            }
            else
            {
                return CreateFallbackRenderer(renderable);
            }
        }

        public IRenderer CreateBodyHookRenderer(BodyHook bodyHook)
        {
            ImageRenderer imageRenderer = CreateSizedImageRenderer(bodyHook, @"Resources\LargeGoo.png", Vector2.Zero, new Vector2(bodyHook.Radius, bodyHook.Radius));
            return imageRenderer;
        }

        public ImageRenderer CreateSizedImageRenderer(Renderable renderable, string fileName, Vector2 offset, Vector2 size)
        {
            ImageRenderer imageRenderer = CreateImageRenderer(renderable, fileName, Vector2.Zero);
            imageRenderer.Image.Width = (double)size.X;
            imageRenderer.Image.Height = (double)size.Y;
            imageRenderer.AdjustOffset();
            return imageRenderer;
        }

        public IRenderer CreateGoalRenderer(Goal goal)
        {
            ImageRenderer imageRenderer = CreateImageRenderer(goal, @"Resources\BlackHoleSpiral.png", Vector2.Zero);
            return imageRenderer;
        }

        public ImageRenderer CreateImageRenderer(Renderable renderable, string fileName, Vector2 offset)
        {
            Image image = CreateImageForFileName(fileName);
            return new ImageRenderer(this, renderable, image, offset);
        }

        public Image CreateImageForFileNameColorized(string fileName, Color color)
        {
            BitmapImage bitmapImage = GetOrCreateBitmapImage(fileName, color);

            Image image = new Image();
            image.Height = bitmapImage.PixelHeight;
            image.Width = bitmapImage.PixelWidth;
            image.Source = bitmapImage;
            return image;
        }

        public IRenderer CreateParticleRenderer(Particle particle)
        {            
            return new ParticleRenderer(this, particle);
        }

        public IRenderer CreateFallbackBodyRenderer(BodyRenderable bodyRenderable)
        {
            return new PolygonRenderer(this, bodyRenderable);
        }

        public IRenderer CreateFallbackRenderer(Renderable worldObject)
        {
            return null;
        }

        public void BeforeUpdate()
        {
        }

        public void AfterUpdate()
        {
        }

        public void DoBeforeCopyLevelToEngine()
        {          
            Canvas.Width = Engine.CurrentLevel.Size.X;
            Canvas.Height = Engine.CurrentLevel.Size.Y;
        }

        public void DoAfterCopyLevelToEngine()
        {            
        }
       
        private Image CreateImageForFileName(string fileName)
        {
            BitmapImage bitmapImage = GetOrCreateBitmapImage(fileName, ColorConstants.White);

            Image image = new Image();
            image.Height = bitmapImage.PixelHeight;
            image.Width = bitmapImage.PixelWidth;
            image.Source = bitmapImage;
            return image;
        }
        
        private IRenderer CreateLinkRenderer(Link link)
        {
            return new LinkRenderer(this, link);
        }
    }
}
